﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using DatabaseGroup.SSIS.SourceAdapters.Parser;

namespace DatabaseGroup.UnitTests.SSIS.SourceAdapters.Parser
{
    [TestClass()]
    public class DelimitedFileParserTest
    {
        private TestContext _testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return _testContextInstance;
            }
            set
            {
                _testContextInstance = value;
            }
        }

        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentNullException), "Expected ArgumentNullException to be thrown when ctor called with 2 empty strings")]
        public void DelimitedFileParser_ConstructorWithEmptyArgs_ThrowArgumentNullException()
        {
            DelimitedFileParser target = new DelimitedFileParser(string.Empty, string.Empty);
        }

        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentNullException), "Expected ArgumentNullException to be thrown when ctor called with 1st arg as null")]
        public void DelimitedFileParser_ConstructorWithNull1stArg_ThrowArgumentNullException()
        {
            DelimitedFileParser target = new DelimitedFileParser(null, string.Empty);
        }

        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentNullException), "Expected ArgumentNullException to be thrown when ctor called with 2nd arg as an empty string")]
        public void DelimitedFileParser_ConstructorWithEmpty2ndArg_ThrowArgumentNullException()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", string.Empty);
        }

        [TestMethod()]
        public void TextQualifier_SetGet_ReturnExpectedValue()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            string expected = "\"";
            string actual;
            target.TextQualifier = expected;
            actual = target.TextQualifier;
            Assert.AreEqual<string>(expected, actual, "Expected value to be a quote text qualifier");
        }

        [TestMethod()]
        public void HeaderRowsToSkip_SetGet_ReturnExpectedValue()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            int expected = 5;
            int actual;
            target.HeaderRowsToSkip = expected;
            actual = target.HeaderRowsToSkip;
            Assert.AreEqual<int>(expected, actual, "Expected value to be number of header rows to skip (5)");
        }

        [TestMethod()]
        public void DataRowsToSkip_SetGet_ReturnExpectedValue()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            int expected = 17;
            int actual;
            target.DataRowsToSkip = expected;
            actual = target.DataRowsToSkip;
            Assert.AreEqual<int>(expected, actual, "Expected value to be number of data rows to skip (17)");
        }

        [TestMethod()]
        public void HeaderRowDelimiter_SetGet_ReturnExpectedValue()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            string expected = "\r\n";
            string actual;
            target.HeaderRowDelimiter = expected;
            actual = target.HeaderRowDelimiter;
            Assert.AreEqual<string>(expected, actual, "Expected HeaderRowDelimiter value to be carriage return line feed");
        }

        [TestMethod()]
        public void ColumnNameInFirstRow_SetGet_ReturnExpectedValue()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            bool expected = false;
            bool actual;
            target.ColumnNameInFirstRow = expected;
            actual = target.ColumnNameInFirstRow;
            Assert.AreEqual<bool>(expected, actual, "Expected ColumnNameInFirstRow value to be set to false");
        }

        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentNullException), "Expected ArgumentNullException to be thrown when ParseNextRow called with null args")]
        public void ParseNextRow_NullArgs_ThrowArgumentNullException()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");

            target.ParseNextRow(null, null);
        }

        [TestMethod()]
        [ExpectedException(typeof(System.ArgumentNullException), "Expected ArgumentNullException to be thrown when SkipHeaderRows called with null arg")]
        public void SkipHeaderRows_NullArg_ThrowArgumentNullException()
        {
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");

            target.SkipHeaderRows(null);
        }

        [TestMethod()]
        public void ParseNextRow_ReadColumnNames_ReturnExpectedColumnHeaderData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("A,B,C\r\n1,2,3");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.ColumnNameInFirstRow = true;

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "A", "B", "C" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadColumnNamesAfterHeaderRows_ReturnExpectedColumnHeaderData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader text\r\nA,B,C\r\n1,2,3");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.ColumnNameInFirstRow = true;
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;

            target.SkipHeaderRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "A", "B", "C" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadQualifiedColumnNamesAfterHeaderRows_ReturnExpectedColumnHeaderData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader text\r\n\"A\",B,\"C\"\r\n1,2,3");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.ColumnNameInFirstRow = true;
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;
            target.TextQualifier = "\"";

            target.SkipHeaderRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "A", "B", "C" });
        }

        [TestMethod()]
        public void ParseNextRow_ValidRowData_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("1,2,3");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "1", "2", "3" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadSingleCharSingleColumnRows_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("1,2,3");
            DelimitedFileParser target = new DelimitedFileParser(string.Empty, ",");

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "1" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "2" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "3" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadMultiCharSingleColumnRows_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("ABC\r\nDEF\r\nGHI");
            DelimitedFileParser target = new DelimitedFileParser(string.Empty, "\r\n");

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "ABC" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "DEF" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "GHI" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadQualifiedMultiCharSingleColumnRows_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\"ABC\"\r\n\"DE\"F\r\n\"G\"HI");
            DelimitedFileParser target = new DelimitedFileParser(string.Empty, "\r\n");
            target.TextQualifier = "\"";

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "ABC" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "DEF" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "GHI" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadMultipleColumnDataRows_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");

            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "1", "1", "1", "1" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "2", "2", "2", "2" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "3", "3", "3", "3" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "4", "4", "4", "4" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadMultipleColumnDataRowsAfterHeaderRows_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader text\r\n1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;

            target.SkipHeaderRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "1", "1", "1", "1" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "2", "2", "2", "2" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "3", "3", "3", "3" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "4", "4", "4", "4" });
        }

        [TestMethod()]
        public void ParseNextRow_ReadMultipleColumnDataRowsWithBlankLastRow_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4\r\n");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");

            target.SkipInitialRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "1", "1", "1", "1" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "2", "2", "2", "2" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "3", "3", "3", "3" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "4", "4", "4", "4" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[0]);
        }

        [TestMethod()]
        public void SkipInitialRows_SkipHeaderAndDataRowsWithDataRowsLeft_ReturnExpectedColumnDataWithoutSkippedRowData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader\r\nA,B,C,D\r\n1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4\r\n");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;
            target.DataRowsToSkip = 3;
            target.ColumnNameInFirstRow = true;

            target.SkipInitialRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "4", "4", "4", "4" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[0]);

            Assert.AreEqual<bool>(true, reader.IsEOF, "Expected file reader to be set to EOF after remaining data rows have been parsed");
        }

        [TestMethod()]
        public void SkipInitialRows_SkipHeaderRowsWithNoDataRowsRemaining_FileReaderIsEOF()
        {
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader\r\nA,B,C,D");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;
            target.ColumnNameInFirstRow = true;

            target.SkipInitialRows(reader);

            Assert.AreEqual<bool>(true, reader.IsEOF, "Expected file reader to be set to EOF once all rows have been skipped and parsed");
        }

        [TestMethod()]
        public void SkipInitialRows_SkipTooManyDataRowsForData_FileReaderIsEOF()
        {
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader\r\nA,B,C,D\r\n1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4\r\n");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;
            target.DataRowsToSkip = 15;
            target.ColumnNameInFirstRow = true;

            target.SkipInitialRows(reader);

            Assert.AreEqual<bool>(true, reader.IsEOF, "Expected file reader to be set to EOF once all rows have been skipped");
        }


        [TestMethod()]
        public void SkipInitialRows_SkipTooManyHeaderRowsForData_FileReaderIsEOF()
        {
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader\r\nA,B,C,D\r\n1,1,1,1\r\n2,2,2,2\r\n3,3,3,3\r\n4,4,4,4\r\n");
            DelimitedFileParser target = new DelimitedFileParser(",", "\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 12;
            target.DataRowsToSkip = 15;
            target.ColumnNameInFirstRow = true;

            target.SkipInitialRows(reader);

            Assert.AreEqual<bool>(true, reader.IsEOF, "Expected file reader to be set to EOF once all rows have been skipped");
        }

        [TestMethod()]
        public void ParseNextRow_ReadMultipleDataRowsAfterHeaderRowsWithMessyParsing_ReturnExpectedColumnData()
        {
            RowData rowData = new RowData();
            IFileReader reader = FileReaderTest.GetReader("\r\n\r\nHeader text\r\n A)::-)brr\"-:-)\r\n-\r\nasdfghj\"-\"\"-\":-)\"-\":-)\"-\"\"-\"\"-\":--\r");
            DelimitedFileParser target = new DelimitedFileParser(":-)", "-\r\n");
            target.HeaderRowDelimiter = "\r\n";
            target.HeaderRowsToSkip = 3;
            target.TextQualifier = "\"-\"";

            target.SkipHeaderRows(reader);
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { " A):", "brr\"-", "\r\n" });
            target.ParseNextRow(reader, rowData);
            RowDataTest.VerifyParsedRow(rowData, new string[] { "asdfghj\"-\"\"-\"", ":-)\"-\":-" });
        }
    }
}
